﻿#include "awtk.h"
#include "hmi.h"
#include "list_ports_awtk.h"
#include "streams/stream_factory.h"
#include "../common/navigator.h"

static port_info_t s_ports[256];

static ret_t window_set_hmi_obj(widget_t* win, hmi_t* hmi) {
  return_value_if_fail(win != NULL, RET_BAD_PARAMS);

  if (hmi == NULL) {
    widget_set_prop_pointer(win, "hmi", NULL);
  } else {
    widget_set_prop_pointer_ex(win, "hmi", hmi, (tk_destroy_t)hmi_destroy);
  }
  widget_set_enable(widget_lookup(win, "connect", TRUE), hmi == NULL);
  widget_set_enable(widget_lookup(win, "disconnect", TRUE), hmi != NULL);

  return RET_OK;
}

static ret_t home_page_append_message(widget_t* win, const char* name, const char* value, bool_t with_new_line) {
  wstr_t wstr;
  char message[1024] = {0};
  widget_t* events = widget_lookup(win, "events", TRUE);

  wstr_init(&wstr, 1000);
  tk_snprintf(message, sizeof(message) - 1, "%s: %s%s", name, value, with_new_line ? "\n" : "");
  wstr_set_utf8(&wstr, message);

  wstr_append(&wstr, widget_get_text(events));

  widget_set_text(events, wstr.str);
  wstr_reset(&wstr);

  return RET_OK;
}

static ret_t home_page_on_prop_change(hmi_t* hmi, const char* name, const value_t* v) {
  char buff[64] = {0};
  widget_t* win = WIDGET(hmi->ctx);
  widget_t* prop_name = widget_lookup(win, "prop_name", TRUE);

  if (!combo_box_has_option_text(prop_name, name)) {
    combo_box_append_option(prop_name, 0, name);
  }

  log_debug("%s\n", name);
  return home_page_append_message(win, name, value_str_ex(v, buff, sizeof(buff) - 1), TRUE);
}

static ret_t home_page_on_clear(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  widget_t* events = widget_lookup(win, "events", TRUE);

  widget_set_text(events, L"");

  return RET_OK;
}

static ret_t home_page_on_log_message(void* ctx, tk_log_level_t level, const char* message) {
  widget_t* win = WIDGET(ctx);
  return_value_if_fail(win != NULL, RET_BAD_PARAMS);
  const char* levels[] = {"debug", "info", "warn", "error"};
  const char* slevel = locale_info_tr(locale_info(), levels[level]);

  return home_page_append_message(win, slevel, message, FALSE);
}

static ret_t home_page_on_enable_log_changed(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  hmi_t* hmi = (hmi_t*)widget_get_prop_pointer(win, "hmi");
  value_change_event_t* evt = value_change_event_cast(e);
  bool_t enable = value_bool(&(evt->new_value));
  return_value_if_fail(hmi != NULL, RET_BAD_PARAMS);

  if (enable) {
    remote_ui_hook_log(hmi->remote_ui, home_page_on_log_message, win);
  } else {
    remote_ui_unhook_log(hmi->remote_ui);
  }

  return RET_OK;
}

static ret_t home_page_on_connect(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  hmi_t* hmi = NULL;
  char url[128] = {0};
  tk_iostream_t* io = NULL;
  uint32_t value = widget_get_value_int(widget_lookup(win, "url", TRUE));

  if (value < ARRAY_SIZE(s_ports)) {
    if (value == 0) {
      tk_snprintf(url, sizeof(url) - 1, STR_SCHEMA_TCP "localhost:2233");
    } else {
      tk_snprintf(url, sizeof(url) - 1, STR_SCHEMA_SERIAL "%s", s_ports[value].name);
    }
  } else {
    dialog_toast("invalid device.", 3000);
    return RET_FAIL;
  }

  io = tk_stream_factory_create_iostream(url);
  if (io == NULL) {
    log_debug("can not create io stream for %s\n", url);
    dialog_toast("connect fail.", 3000);
    return RET_FAIL;
  } else {
    log_debug("create io stream for %s\n", url);
  }

  hmi = hmi_create(io, home_page_on_prop_change, win);
  if (hmi == NULL) {
    log_debug("can not create hmi for %s\n", url);
    TK_OBJECT_UNREF(io);
    return RET_FAIL;
  }

  if (widget_get_value_int(widget_lookup(win, "enable_log", TRUE))) {
    remote_ui_hook_log(hmi->remote_ui, home_page_on_log_message, win);
  }

  window_set_hmi_obj(win, hmi);

  return RET_OK;
}

static ret_t home_page_on_disconnect(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  window_set_hmi_obj(win, NULL);

  return RET_OK;
}

static ret_t timer_dispatch_events(const timer_info_t* info) {
  widget_t* win = WIDGET(info->ctx);
  hmi_t* hmi = (hmi_t*)widget_get_prop_pointer(win, "hmi");

  if (hmi != NULL) {
    if (hmi_dispatch(hmi) == RET_IO) {
      window_set_hmi_obj(win, NULL);
    }
  }

  return RET_REPEAT;
}

static ret_t home_page_on_get_prop(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  hmi_t* hmi = (hmi_t*)widget_get_prop_pointer(win, "hmi");

  if (hmi != NULL) {
    value_t v;
    int type = 0;
    char prop_name[128] = {0};
    char prop_value[1024] = {0};

    value_set_int32(&v, 0);
    widget_get_child_text_utf8(win, "prop_name", prop_name, sizeof(prop_name) - 1);

    if (hmi_get_prop(hmi, STR_GLOBAL_MODEL, prop_name, &v) == RET_OK) {
      widget_set_child_text_utf8(win, "prop_value",
                                 value_str_ex(&v, prop_value, sizeof(prop_value) - 1));
    }

    switch (v.type) {
      case VALUE_TYPE_INT32:
        type = 0;
        break;
      case VALUE_TYPE_FLOAT:
        type = 1;
        break;
      case VALUE_TYPE_BOOL:
        type = 2;
        break;
      case VALUE_TYPE_STRING:
        type = 3;
        break;
      case VALUE_TYPE_INT64:
        type = 4;
        break;
      default:
        break;
    }

    widget_set_value_int(widget_lookup(win, "prop_type", TRUE), type);
  } else {
    dialog_toast("please connect first.", 3000);
    log_debug("hmi is null\n");
  }

  return RET_OK;
}

static ret_t home_page_on_set_prop(void* ctx, event_t* e) {
  widget_t* win = WIDGET(ctx);
  hmi_t* hmi = (hmi_t*)widget_get_prop_pointer(win, "hmi");

  if (hmi != NULL) {
    char prop_name[128] = {0};
    char prop_value[1024] = {0};

    widget_get_child_text_utf8(win, "prop_name", prop_name, sizeof(prop_name) - 1);
    widget_get_child_text_utf8(win, "prop_value", prop_value, sizeof(prop_value) - 1);
    int type = widget_get_value_int(widget_lookup(win, "prop_type", TRUE));

    switch (type) {
      case 0:
        hmi_set_prop_int(hmi, prop_name, tk_atoi(prop_value));
        break;
      case 1:
        hmi_set_prop_float(hmi, prop_name, tk_atof(prop_value));
        break;
      case 2:
        hmi_set_prop_bool(hmi, prop_name, tk_atoi(prop_value));
        break;
      case 3:
        hmi_set_prop_str(hmi, prop_name, prop_value);
        break;
      case 4:
        hmi_set_prop_int64(hmi, prop_name, tk_atol(prop_value));
      default:
        break;
    }
  } else {
    dialog_toast("please connect first.", 3000);
    log_debug("hmi is null\n");
  }

  return RET_OK;
}

static ret_t home_page_is_connected(widget_t* win) {
  hmi_t* hmi = (hmi_t*)widget_get_prop_pointer(win, "hmi");

  return hmi != NULL;
}

static ret_t home_page_refresh_devices(widget_t* win, bool_t select_first) {
  int i = 0;
  widget_t* target = NULL;
  return_value_if_fail(win != NULL, RET_BAD_PARAMS);

  if (home_page_is_connected(win)) {
    return RET_OK;
  }

  target = widget_lookup(win, "url", TRUE);
  memset(s_ports, 0x00, sizeof(s_ports));
  combo_box_reset_options(target);
  tk_strcpy(s_ports[0].name, "localhost");
  tk_strcpy(s_ports[0].desc, "Localhost:2233");
  tk_list_ports(s_ports + 1, ARRAY_SIZE(s_ports) - 1);

  for (i = 0; i < ARRAY_SIZE(s_ports); i++) {
    if (s_ports[i].name[0] != '\0') {
      combo_box_append_option(target, i, s_ports[i].desc);
    }
  }

  if (select_first) {
    combo_box_set_selected_index(target, 0);
  }

  return RET_OK;
}

static ret_t home_page_refresh_devices_timer(const timer_info_t* info) {
  widget_t* win = WIDGET(info->ctx);

  home_page_refresh_devices(win, FALSE);

  return RET_REPEAT;
}

static ret_t home_page_refresh_devices_idle(const idle_info_t* info) {
  widget_t* win = WIDGET(info->ctx);

  home_page_refresh_devices(win, TRUE);
  widget_add_timer(win, home_page_refresh_devices_timer, 2000);

  return RET_REMOVE;
}

/**
 * 初始化窗口
 */
ret_t home_page_init(widget_t* win, void* ctx) {
  return_value_if_fail(win != NULL, RET_BAD_PARAMS);

  widget_child_on(win, "connect", EVT_CLICK, home_page_on_connect, win);
  widget_child_on(win, "disconnect", EVT_CLICK, home_page_on_disconnect, win);
  widget_child_on(win, "set_prop", EVT_CLICK, home_page_on_set_prop, win);
  widget_child_on(win, "get_prop", EVT_CLICK, home_page_on_get_prop, win);
  widget_child_on(win, "enable_log", EVT_VALUE_CHANGED, home_page_on_enable_log_changed, win);
  widget_child_on(win, "clear", EVT_CLICK, home_page_on_clear, win);

  widget_add_timer(win, timer_dispatch_events, 20);

  idle_add(home_page_refresh_devices_idle, win);

  return RET_OK;
}
